package com.ccrfid.rmc6.service.sys;

import com.ccrfid.rmc6.appconfig.exception.pojo.AppException;
import com.ccrfid.rmc6.appconfig.exception.pojo.CustomErrors;
import com.ccrfid.rmc6.entity.device.LocatorEntity;
import com.ccrfid.rmc6.entity.personnel.PersonnelEntity;
import com.ccrfid.rmc6.entity.personnel.PersonnelMoveEntity;
import com.ccrfid.rmc6.entity.personnel.PersonnelPrisonerView;
import com.ccrfid.rmc6.entity.personnel.PersonnelView;
import com.ccrfid.rmc6.entity.poi.PoiLocationEntity;
import com.ccrfid.rmc6.entity.sys.LocationPersonnelActivityEntity;
import com.ccrfid.rmc6.entity.sys.OrgEntity;
import com.ccrfid.rmc6.entity.sys.RoomManagerEntity;
import com.ccrfid.rmc6.pojo.dto.MoveInLocationDto;
import com.ccrfid.rmc6.pojo.dto.PersonnelMoveDto;
import com.ccrfid.rmc6.pojo.dto.TimeRecord;
import com.ccrfid.rmc6.pojo.dto.room.PersonnelInOutRecord;
import com.ccrfid.rmc6.pojo.dto.room.RoomManagerDto;
import com.ccrfid.rmc6.pojo.dto.room.RoomPrisonerDto;
import com.ccrfid.rmc6.pojo.dto.room.RoomSummaryDto;
import com.ccrfid.rmc6.repository.personnel.PersonnelPrisonerViewRepository;
import com.ccrfid.rmc6.repository.personnel.PersonnelRepository;
import com.ccrfid.rmc6.repository.personnel.PersonnelViewRepository;
import com.ccrfid.rmc6.repository.poi.PoiLocationRepository;
import com.ccrfid.rmc6.repository.sys.LocationPersonnelActivityRepository;
import com.ccrfid.rmc6.repository.sys.OrgRepository;
import com.ccrfid.rmc6.repository.sys.RoomManagerRepository;
import com.ccrfid.rmc6.service.poi.PoiService;
import com.ccrfid.rmc6.util.GeomUtil;
import com.vividsolutions.jts.geom.Point;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.transaction.Transactional;
import javax.ws.rs.core.Response;
import java.sql.Timestamp;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Transactional
public class RoomServiceImpl implements RoomService {
    private static final Logger logger = LoggerFactory.getLogger(RoomServiceImpl.class);
    @Autowired
    private RoomManagerRepository roomManagerRepository;
    @Autowired
    private PersonnelRepository personnelRepository;
    @Autowired
    private PersonnelViewRepository personnelViewRepository;
    @Autowired
    private PersonnelPrisonerViewRepository personnelPrisonerViewRepository;
    @Autowired
    private OrgRepository orgRepository;
    @Autowired
    private PoiLocationRepository poiLocationRepository;
    @Autowired
    private LocationPersonnelActivityRepository locationPersonnelActivityRepository;
    @PersistenceContext
    private EntityManager entityManager;
    @Autowired
    private PoiService poiService;

    @Override
    public List<RoomManagerDto> getRoomManagers(Long roomId) {
        List<RoomManagerDto> list = new ArrayList<>();
        List<RoomManagerEntity> managerEntities = roomManagerRepository.getByOrgId(roomId);
        if (managerEntities != null && managerEntities.size() > 0) {
            for (RoomManagerEntity entity : managerEntities) {
                RoomManagerDto dto = new RoomManagerDto();
                dto.setManager(entity);
                PersonnelView personnelView = personnelViewRepository.getById(entity.getPersonnelId());
                dto.setManagerDetail(personnelView);
                list.add(dto);
            }
        }
        return list;
    }

    @Override
    public RoomManagerDto getRoomManager(Long roomManagerId) throws AppException {
        if (!roomManagerRepository.existsById(roomManagerId)) {
            throw new AppException(Response.Status.NOT_FOUND.getStatusCode(),
                    CustomErrors.resource_not_found.getCode(), CustomErrors.resource_not_found.getReason(), "");
        }
        RoomManagerDto dto = new RoomManagerDto();
        RoomManagerEntity roomManagerEntity = roomManagerRepository.getById(roomManagerId);
        dto.setManager(roomManagerEntity);
        if (roomManagerEntity.getPersonnelId() != null) {
            PersonnelView personnelView = personnelViewRepository.getById(roomManagerEntity.getPersonnelId());
            dto.setManagerDetail(personnelView);
        }
        return dto;
    }

    @Override
    public RoomManagerDto createRoomManager(RoomManagerEntity entity) throws AppException {
        checkOrg(entity.getOrgId());
        checkPersonnel(entity.getPersonnelId());
        RoomManagerEntity roomManagerEntity = roomManagerRepository.save(entity);
        PersonnelView personnelView = personnelViewRepository.getById(entity.getPersonnelId());

        RoomManagerDto dto = new RoomManagerDto();
        dto.setManager(roomManagerEntity);
        dto.setManagerDetail(personnelView);
        return dto;
    }

    @Override
    public RoomManagerDto updateRoomManager(Long roomManagerId, RoomManagerEntity entity) throws AppException {
        if (!roomManagerId.equals(entity.getId())) {
            throw new AppException(Response.Status.BAD_REQUEST.getStatusCode(),
                    CustomErrors.different_args.getCode(), CustomErrors.different_args.getReason(), "");
        }
        checkPersonnel(entity.getPersonnelId());
        RoomManagerEntity roomManagerEntity = roomManagerRepository.save(entity);
        PersonnelView personnelView = personnelViewRepository.getById(entity.getPersonnelId());

        RoomManagerDto dto = new RoomManagerDto();
        dto.setManager(roomManagerEntity);
        dto.setManagerDetail(personnelView);
        return dto;
    }

    @Override
    public Boolean deleteRoomManager(Long roomManagerId) {
        roomManagerRepository.deleteById(roomManagerId);
        return true;
    }

    private void checkOrg(Long orgId) throws AppException {
        if (!orgRepository.existsById(orgId)) {
            throw new AppException(Response.Status.NOT_FOUND.getStatusCode(),
                    CustomErrors.org_not_found.getCode(), CustomErrors.org_not_found.getReason(), "");
        }
        OrgEntity orgEntity = orgRepository.getById(orgId);
        if (!orgEntity.getOrgType().equals(602)) {
            throw new AppException(Response.Status.BAD_REQUEST.getStatusCode(),
                    CustomErrors.org_type_mistake.getCode(), CustomErrors.org_type_mistake.getReason(), "");
        }
    }

    private void checkPersonnel(Long personnelId) throws AppException {
        if (!personnelViewRepository.existsById(personnelId)) {
            throw new AppException(Response.Status.NOT_FOUND.getStatusCode(),
                    CustomErrors.person_not_found.getCode(), CustomErrors.person_not_found.getReason(), "");
        }
        PersonnelView personnelView = personnelViewRepository.getById(personnelId);
        if (!personnelView.getPersonnelType().equals(104)) {
            throw new AppException(Response.Status.BAD_REQUEST.getStatusCode(),
                    CustomErrors.person_type_mistake.getCode(), CustomErrors.person_type_mistake.getReason(), "");
        }
    }

    @Override
    public RoomSummaryDto getRoomSummary(Long roomId) {
        RoomSummaryDto dto = new RoomSummaryDto();
        List<PersonnelPrisonerView> list = personnelPrisonerViewRepository.getByOrgIdAndEnabled(roomId, 1);
        dto.setTotalPrisonerCount(list.size());
        for (PersonnelPrisonerView prisonerView : list) {
            if (prisonerView.getIsDeathPrisoner() != null && prisonerView.getIsDeathPrisoner().equals(1)) {
                dto.addDeathPrisonerCount();
            }
            if (prisonerView.getIsMajorCriminalOffender() != null && prisonerView.getIsMajorCriminalOffender().equals(1)) {
                dto.addMajorCriminalOffenderCount();
            }
            if (prisonerView.getIsInfectedPrisoner() != null && prisonerView.getIsInfectedPrisoner().equals(1)) {
                dto.addInfectedPrisonerCount();
            }
            if (prisonerView.getIsFocusedPrisoner() != null && prisonerView.getIsFocusedPrisoner().equals(1)) {
                dto.addFocusedPrisonerCount();
            }
        }
        return dto;
    }

    private PoiLocationEntity getPrisoner3LevelLocation(PersonnelPrisonerView prisoner) {
        PoiLocationEntity locationEntity =
                poiLocationRepository.get3LevelLocationContainsPoint(prisoner.getFloorNumber(), prisoner.getPos());
        return locationEntity;
    }

    @Override
    public List<RoomPrisonerDto> getImportantPrisoners(Long roomId) {
        List<RoomPrisonerDto> list = new ArrayList<>();
        List<PersonnelPrisonerView> prisonerViewList = personnelPrisonerViewRepository.getImportantPrisonersByOrgId(roomId);
        for (PersonnelPrisonerView prisoner : prisonerViewList) {
            RoomPrisonerDto dto = new RoomPrisonerDto();
            dto.setPrisonerDetail(prisoner);
            dto.setCurrentLocation(getPrisoner3LevelLocation(prisoner));
            list.add(dto);
        }
        return list;
    }

    @Override
    public List<RoomPrisonerDto> getPrisoners(Long roomId) {
        List<RoomPrisonerDto> list = new ArrayList<>();
        List<PersonnelPrisonerView> prisonerViewList = personnelPrisonerViewRepository.getByOrgIdAndEnabled(roomId, 1);
        for (PersonnelPrisonerView prisoner : prisonerViewList) {
            RoomPrisonerDto dto = new RoomPrisonerDto();
            dto.setPrisonerDetail(prisoner);
            dto.setCurrentLocation(getPrisoner3LevelLocation(prisoner));
            list.add(dto);
        }
        return list;
    }

    @Override
    public List<RoomPrisonerDto> getLeavedPrisoners(Long roomId) {
        List<RoomPrisonerDto> list = new ArrayList<>();
        List<PoiLocationEntity> bindLocationList = poiLocationRepository.getByBindOrgId(roomId);
        if (bindLocationList.size() > 0) {
            List<PersonnelPrisonerView> prisonerList = personnelPrisonerViewRepository.getByOrgIdAndEnabled(roomId, 1);
            for (PersonnelPrisonerView prisonerView : prisonerList) {
                PoiLocationEntity currentLocation = getPrisoner3LevelLocation(prisonerView);
                if (currentLocation != null) {
                    if (!containLocation(bindLocationList, currentLocation)) {
                        RoomPrisonerDto dto = new RoomPrisonerDto();
                        dto.setPrisonerDetail(prisonerView);
                        dto.setCurrentLocation(currentLocation);
                        list.add(dto);
                    }
                } else {
                    RoomPrisonerDto dto = new RoomPrisonerDto();
                    dto.setPrisonerDetail(prisonerView);
                    dto.setCurrentLocation(null);
                    list.add(dto);
                }
            }
            return list;
        } else {
            return list;
        }
    }

    private boolean containLocation(List<PoiLocationEntity> bindLocationList, PoiLocationEntity locationEntity) {
        for (PoiLocationEntity entity : bindLocationList) {
            if (entity.getId().equals(locationEntity.getId())) {
                return true;
            }
        }
        return false;
    }

    @Override
    public RoomPrisonerDto getPrisonerDetail(Long personnelId) {
        PersonnelPrisonerView prisonerView = personnelPrisonerViewRepository.getById(personnelId);
        RoomPrisonerDto dto = new RoomPrisonerDto();
        dto.setPrisonerDetail(prisonerView);
        dto.setCurrentLocation(getPrisoner3LevelLocation(prisonerView));
        return dto;
    }

    private List<PersonnelMoveDto> getPersonnelMoveList(Long personnelId, String startTime, String endTime) {
        String sql = "select m.id, m.personnel_id, m.card_number, m.front_locator_address, m.current_locator_address, " +
                " m.record_time, p.id as location_id, p.location_name, p.location_type, p.map_level, p.location_centroid," +
                " p.floor_number, p.bind_org_id " +
                " from personnel_move m " +
                " left join (select * from poi_location where map_level = 3) p " +
                " on st_contains(p.location_polygon, point(m.current_x, m.current_y)) and p.floor_number = m.current_floor_number " +
                " where m.personnel_id = :perid " +
                " and (m.record_time BETWEEN '" + startTime + "' and '" + endTime + "') " +
                " order by m.id";
        List<PersonnelMoveDto> moveList = entityManager.createNativeQuery(sql, PersonnelMoveDto.class)
                .setParameter("perid", personnelId)
                .getResultList();
        return moveList;
    }

    @Override
    public List<MoveInLocationDto> getPersonnelActivityHistory(Long personnelId, String dateStr) {
        String startTime = dateStr + " 00:00:00";
        String endTime = dateStr + " 23:59:59";
        List<PersonnelMoveDto> moveList = getPersonnelMoveList(personnelId, startTime, endTime);
        if (moveList.size() > 0) {
            List<MoveInLocationDto> list = new ArrayList<>();
            int pos = 0;
            for (int i = 0; i < moveList.size(); i++) {
                PersonnelMoveDto moveDto = moveList.get(i);
                if (moveDto.getLocationId() != null) {
                    list.add(createMoveInLocationDto(moveDto));
                    pos = i;
                    break;
                }
            }
            for (int i = pos + 1; i < moveList.size(); i++) {
                MoveInLocationDto dto = list.get(list.size() - 1);
                PersonnelMoveDto frontDto = moveList.get(i - 1);
                PersonnelMoveDto currentDto = moveList.get(i);
                if (frontDto.getLocationId() != null) {
                    dto.setLeaveTime(currentDto.getRecordTime());
                }
                if ((currentDto.getLocationId() != null && !currentDto.getLocationId().equals(dto.getLocationId()))
                        || (currentDto.getLocationId() != null && frontDto.getLocationId() == null)) {
                    list.add(createMoveInLocationDto(currentDto));
                }
            }
            //获取停留区域的行为状态，并剔除没有行为的记录
            PersonnelEntity personnelEntity = personnelRepository.getById(personnelId);
            Iterator<MoveInLocationDto> iterator = list.iterator();
            while (iterator.hasNext()) {
                MoveInLocationDto dto = iterator.next();
                String activityName = getActivityName(personnelEntity.getPersonnelType(), dto.getLocationType(), dto.getEnterTime());
                if (activityName != null) {
                    dto.setActivityName(activityName);
                } else {
                    iterator.remove();
                }
            }
            return list;
        } else {
            return new ArrayList<>();
        }
    }

    @Override
    public List<MoveInLocationDto> getPersonnelMoveLocationList(Long personnelId, String startTime, String endTime) {
        List<PersonnelMoveDto> moveList = getPersonnelMoveList(personnelId, startTime, endTime);
        if (moveList.size() > 0) {
            List<MoveInLocationDto> list = new ArrayList<>();
            int pos = 0;
            for (int i = 0; i < moveList.size(); i++) {
                PersonnelMoveDto moveDto = moveList.get(i);
                if (moveDto.getLocationId() != null) {
                    list.add(createMoveInLocationDto(moveDto));
                    pos = i;
                    break;
                }
            }
            for (int i = pos + 1; i < moveList.size(); i++) {
                MoveInLocationDto dto = list.get(list.size() - 1);
                PersonnelMoveDto frontDto = moveList.get(i - 1);
                PersonnelMoveDto currentDto = moveList.get(i);
                if (frontDto.getLocationId() != null) {
                    dto.setLeaveTime(currentDto.getRecordTime());
                }
                if ((currentDto.getLocationId() != null && !currentDto.getLocationId().equals(dto.getLocationId()))
                        || (currentDto.getLocationId() != null && frontDto.getLocationId() == null)) {
                    list.add(createMoveInLocationDto(currentDto));
                }
            }
            //获取停留区域的行为状态
            PersonnelEntity personnelEntity = personnelRepository.getById(personnelId);
            for (MoveInLocationDto dto : list) {
                String activityName = getActivityName(personnelEntity.getPersonnelType(), dto.getLocationType(), dto.getEnterTime());
                if (activityName != null) {
                    dto.setActivityName(activityName);
                }
            }
            return list;
        } else {
            return new ArrayList<>();
        }
    }

    private String getActivityName(Integer personnelType, Integer locationType, Timestamp timestamp) {
        List<LocationPersonnelActivityEntity> activityEntityList =
                locationPersonnelActivityRepository.getActivityEntity(personnelType, locationType, timestamp);
        if (activityEntityList.size() > 0) {
            return activityEntityList.get(0).getActivityTypeName();
        } else {
            return null;
        }
    }

    private MoveInLocationDto createMoveInLocationDto(PersonnelMoveDto moveDto) {
        MoveInLocationDto moveInLocationDto = new MoveInLocationDto();
        moveInLocationDto.setPersonnelId(moveDto.getPersonnelId());
        moveInLocationDto.setCardNumber(moveDto.getCardNumber());
        moveInLocationDto.setLocationId(moveDto.getLocationId());
        moveInLocationDto.setLocationName(moveDto.getLocationName());
        moveInLocationDto.setLocationType(moveDto.getLocationType());
        moveInLocationDto.setLocationCentroid(moveDto.getLocationCentroid());
        moveInLocationDto.setFloorNumber(moveDto.getFloorNumber());
        moveInLocationDto.setEnterTime(moveDto.getRecordTime());
        return moveInLocationDto;
    }

    @Override
    public List<PersonnelInOutRecord> getRoomLeaveRecords(Long roomId, String dateStr) {
        Set<Integer> locatorSet = getLocatorInRoom(roomId);
        if (locatorSet.size() > 0) {
            List<PersonnelInOutRecord> list = new ArrayList<>();
            List<PersonnelView> personnelList = personnelViewRepository.getAllByOrgId(roomId);
            for (PersonnelView personnelView : personnelList) {
                List<TimeRecord> timeRecordList = getPersonnelLeaveRecords(personnelView.getId(), dateStr, locatorSet);
                if (timeRecordList.size() > 0) {
                    PersonnelInOutRecord personnelInOutRecord = new PersonnelInOutRecord();
                    personnelInOutRecord.setPersonnelInfo(personnelView);
                    personnelInOutRecord.setTimeRecordList(timeRecordList);
                    list.add(personnelInOutRecord);
                }
            }
            return list;
        } else {
            return new ArrayList<>();
        }
    }

    @Override
    public List<PersonnelInOutRecord> getRoomLeaveRecords2(Long roomId, String dateStr) {
        List<PoiLocationEntity> locationList = poiLocationRepository.getByBindOrgId(roomId);
        if (locationList != null && locationList.size() > 0) {
            List<PersonnelInOutRecord> list = new ArrayList<>();
            List<PersonnelView> personnelList = personnelViewRepository.getAllByOrgId(roomId);
            for (PersonnelView personnelView : personnelList) {
                List<TimeRecord> timeRecordList = getPersonnelLeaveRecords(personnelView.getId(), dateStr, locationList);
                if (timeRecordList.size() > 0) {
                    PersonnelInOutRecord personnelInOutRecord = new PersonnelInOutRecord();
                    personnelInOutRecord.setPersonnelInfo(personnelView);
                    personnelInOutRecord.setTimeRecordList(timeRecordList);
                    list.add(personnelInOutRecord);
                }
            }
            return list;
        } else {
            return new ArrayList<>();
        }
    }

    @Override
    public List<PersonnelInOutRecord> getRoomEnterRecords(Long roomId, String dateStr) {
        Set<Integer> locatorSet = getLocatorInRoom(roomId);
        if (locatorSet.size() > 0) {
            List<PersonnelInOutRecord> list = new ArrayList<>();
            List<PersonnelView> personnelList = getPersonnelListNotBindRoom(roomId, dateStr, locatorSet);
            for (PersonnelView personnelView : personnelList) {
                List<TimeRecord> timeRecordList = getPersonnelEnterRecords(personnelView.getId(), dateStr, locatorSet);
                if (timeRecordList.size() > 0) {
                    PersonnelInOutRecord personnelInOutRecord = new PersonnelInOutRecord();
                    personnelInOutRecord.setPersonnelInfo(personnelView);
                    personnelInOutRecord.setTimeRecordList(timeRecordList);
                    list.add(personnelInOutRecord);
                }
            }
            return list;
        } else {
            return new ArrayList<>();
        }
    }

    @Override
    public List<PersonnelInOutRecord> getRoomEnterRecords2(Long roomId, String dateStr) {
        List<PoiLocationEntity> locationList = poiLocationRepository.getByBindOrgId(roomId);
        if (locationList != null && locationList.size() > 0) {
            List<PersonnelInOutRecord> list = new ArrayList<>();
            List<PersonnelView> personnelList = getPersonnelListNotBindRoom(roomId, dateStr, locationList);
            for (PersonnelView personnelView : personnelList) {
                List<TimeRecord> timeRecordList = getPersonnelEnterRecords(personnelView.getId(), dateStr, locationList);
                if (timeRecordList.size() > 0) {
                    PersonnelInOutRecord personnelInOutRecord = new PersonnelInOutRecord();
                    personnelInOutRecord.setPersonnelInfo(personnelView);
                    personnelInOutRecord.setTimeRecordList(timeRecordList);
                    list.add(personnelInOutRecord);
                }
            }
            return list;
        } else {
            return new ArrayList<>();
        }
    }

    @Override
    public Set<Integer> getLocatorInRoom(Long roomId) {
        List<PoiLocationEntity> locationEntities = poiLocationRepository.getByBindOrgId(roomId);
        if (locationEntities.size() > 0) {
            Set<Integer> locatorSet = new HashSet<>();
            for (PoiLocationEntity locationEntity : locationEntities) {
                List<LocatorEntity> locatorEntityList = poiService.getLocatorsInLocation(locationEntity);
                if (locatorEntityList.size() > 0) {
                    for (LocatorEntity locatorEntity : locatorEntityList) {
                        locatorSet.add(locatorEntity.getLocatorAddress());
                    }
                }
            }
            return locatorSet;
        } else {
            return new HashSet<>();
        }
    }

    private List<TimeRecord> getPersonnelLeaveRecords(Long personnelId, String dateStr, Set<Integer> locatorSet) {
        String sql = "SELECT * FROM personnel_move where personnel_id = :perid and (record_time between :start and :end)";
        List<PersonnelMoveEntity> moveList = entityManager.createNativeQuery(sql, PersonnelMoveEntity.class)
                .setParameter("perid", personnelId)
                .setParameter("start", dateStr + " 00:00:00")
                .setParameter("end", dateStr + " 23:59:59")
                .getResultList();
        if (moveList.size() > 0) {
            List<TimeRecord> list = new ArrayList<>();
            for (PersonnelMoveEntity moveEntity : moveList) {
                if (locatorSet.contains(moveEntity.getFrontLocatorAddress())
                        && !locatorSet.contains(moveEntity.getCurrentLocatorAddress())) {
                    list.add(new TimeRecord(moveEntity.getRecordTime(), null));
                }
                if (!locatorSet.contains(moveEntity.getFrontLocatorAddress())
                        && locatorSet.contains(moveEntity.getCurrentLocatorAddress())) {
                    if (list.size() > 0) {
                        TimeRecord timeRecord = list.get(list.size() - 1);
                        timeRecord.setStopTime(moveEntity.getRecordTime());
                    }
                }
            }
            return list;
        } else {
            return new ArrayList<>();
        }
    }

    private List<TimeRecord> getPersonnelLeaveRecords(Long personnelId, String dateStr, List<PoiLocationEntity> locationList) {
        String sql = "SELECT * FROM personnel_move where personnel_id = :perid and (record_time between :start and :end)";
        List<PersonnelMoveEntity> moveList = entityManager.createNativeQuery(sql, PersonnelMoveEntity.class)
                .setParameter("perid", personnelId)
                .setParameter("start", dateStr + " 00:00:00")
                .setParameter("end", dateStr + " 23:59:59")
                .getResultList();
        if (moveList.size() > 0) {
            List<TimeRecord> list = new ArrayList<>();
            for (PersonnelMoveEntity moveEntity : moveList) {
                Point currentPos = GeomUtil.INSTANCE.createPoint(moveEntity.getCurrentX(), moveEntity.getCurrentY());
                Point frontPos = GeomUtil.INSTANCE.createPoint(moveEntity.getFrontX(), moveEntity.getFrontY());
                //前一个位置在区域内，当前位置不在区域内
                if (locationContainsPos(locationList, moveEntity.getFrontFloorNumber(), frontPos)
                        && !locationContainsPos(locationList, moveEntity.getCurrentFloorNumber(), currentPos)) {
                    list.add(new TimeRecord(moveEntity.getRecordTime(), null));
                }
                //前一个位置在区域内，当前位置不在区域内
                if (!locationContainsPos(locationList, moveEntity.getFrontFloorNumber(), frontPos)
                        && locationContainsPos(locationList, moveEntity.getCurrentFloorNumber(), currentPos)) {
                    if (list.size() > 0) {
                        TimeRecord timeRecord = list.get(list.size() - 1);
                        timeRecord.setStopTime(moveEntity.getRecordTime());
                    }
                }
            }
            return list;
        } else {
            return new ArrayList<>();
        }
    }

    private boolean locationContainsPos(List<PoiLocationEntity> locationList, Integer floorNumber, Point pos) {
        if (pos == null) {
            return false;
        }
        for (PoiLocationEntity locationEntity : locationList) {
            if (locationEntity.getLocationPolygon().contains(pos)
                    && locationEntity.getFloorNumber().equals(floorNumber)) {
                return true;
            }
        }
        return false;
    }

    //查找未绑定该区域但是进入过该区域的人员
    private List<PersonnelView> getPersonnelListNotBindRoom(Long roomId, String dateStr, Set<Integer> locatorSet) {
        List<PersonnelView> personnelList = personnelViewRepository.getAllByOrgId(roomId);
        List<Long> idList = new ArrayList<>();
        for (PersonnelView personnelView : personnelList) {
            idList.add(personnelView.getId());
        }
        String sql = "SELECT distinct personnel_id FROM personnel_move " +
                " where (record_time between :start and :end)" +
                " and personnel_id not in :idList " +
                " and (front_locator_address in :locatorList or current_locator_address in :locatorList)";
        List<Integer> personnelIdList = entityManager.createNativeQuery(sql)
                .setParameter("start", dateStr + " 00:00:00")
                .setParameter("end", dateStr + " 23:59:59")
                .setParameter("idList", idList)
                .setParameter("locatorList", locatorSet)
                .getResultList();
        List<Long> list = new ArrayList<>();
        for (Integer id : personnelIdList) {
            list.add(id.longValue());
        }
        return personnelViewRepository.getAllByIdIn(list);
    }

    //查找未绑定该区域但是进入过该区域的人员
    private List<PersonnelView> getPersonnelListNotBindRoom(Long roomId, String dateStr, List<PoiLocationEntity> locationList) {
        List<PersonnelView> personnelList = personnelViewRepository.getAllByOrgId(roomId);
        List<Long> idList = new ArrayList<>();
        for (PersonnelView personnelView : personnelList) {
            idList.add(personnelView.getId());
        }
        String sql = "SELECT * FROM personnel_move " +
                " where (record_time between :start and :end)" +
                " and personnel_id not in :idList ";
        List<PersonnelMoveEntity> moveList = entityManager.createNativeQuery(sql)
                .setParameter("start", dateStr + " 00:00:00")
                .setParameter("end", dateStr + " 23:59:59")
                .setParameter("idList", idList)
                .getResultList();

        Set<Long> personnelIdSet = moveList.parallelStream()
                .filter(moveEntity -> {
                    Point frontPos = GeomUtil.INSTANCE.createPoint(moveEntity.getFrontX(), moveEntity.getFrontY());
                    Point currentPos = GeomUtil.INSTANCE.createPoint(moveEntity.getCurrentX(), moveEntity.getCurrentY());
                    return locationContainsPos(locationList, moveEntity.getFrontFloorNumber(), frontPos)
                            || locationContainsPos(locationList, moveEntity.getCurrentFloorNumber(), currentPos);
                })
                .mapToLong(moveEntity -> moveEntity.getPersonnelId())
                .boxed()
                .collect(Collectors.toSet());

        return personnelViewRepository.getAllByIdIn(personnelIdSet);
    }

    private List<TimeRecord> getPersonnelEnterRecords(Long personnelId, String dateStr, Set<Integer> locatorSet) {
        String sql = "SELECT * FROM personnel_move where personnel_id = :perid and (record_time between :start and :end)";
        List<PersonnelMoveEntity> moveList = entityManager.createNativeQuery(sql, PersonnelMoveEntity.class)
                .setParameter("perid", personnelId)
                .setParameter("start", dateStr + " 00:00:00")
                .setParameter("end", dateStr + " 23:59:59")
                .getResultList();
        if (moveList.size() > 0) {
            List<TimeRecord> list = new ArrayList<>();
            for (PersonnelMoveEntity moveEntity : moveList) {
                if (!locatorSet.contains(moveEntity.getFrontLocatorAddress())
                        && locatorSet.contains(moveEntity.getCurrentLocatorAddress())) {
                    list.add(new TimeRecord(moveEntity.getRecordTime(), null));
                }
                if (locatorSet.contains(moveEntity.getFrontLocatorAddress())
                        && !locatorSet.contains(moveEntity.getCurrentLocatorAddress())) {
                    if (list.size() > 0) {
                        TimeRecord timeRecord = list.get(list.size() - 1);
                        timeRecord.setStopTime(moveEntity.getRecordTime());
                    }
                }
            }
            return list;
        } else {
            return new ArrayList<>();
        }
    }

    private List<TimeRecord> getPersonnelEnterRecords(Long personnelId, String dateStr, List<PoiLocationEntity> locationList) {
        String sql = "SELECT * FROM personnel_move where personnel_id = :perid and (record_time between :start and :end)";
        List<PersonnelMoveEntity> moveList = entityManager.createNativeQuery(sql, PersonnelMoveEntity.class)
                .setParameter("perid", personnelId)
                .setParameter("start", dateStr + " 00:00:00")
                .setParameter("end", dateStr + " 23:59:59")
                .getResultList();
        if (moveList.size() > 0) {
            List<TimeRecord> list = new ArrayList<>();
            for (PersonnelMoveEntity moveEntity : moveList) {
                Point currentPos = GeomUtil.INSTANCE.createPoint(moveEntity.getCurrentX(), moveEntity.getCurrentY());
                Point frontPos = GeomUtil.INSTANCE.createPoint(moveEntity.getFrontX(), moveEntity.getFrontY());
                //前一个位置在区域内，当前位置不在区域内
                if (!locationContainsPos(locationList, moveEntity.getFrontFloorNumber(), frontPos)
                        && locationContainsPos(locationList, moveEntity.getCurrentFloorNumber(), currentPos)) {
                    list.add(new TimeRecord(moveEntity.getRecordTime(), null));
                }
                //前一个位置在区域内，当前位置不在区域内
                if (locationContainsPos(locationList, moveEntity.getFrontFloorNumber(), frontPos)
                        && !locationContainsPos(locationList, moveEntity.getCurrentFloorNumber(), currentPos)) {
                    if (list.size() > 0) {
                        TimeRecord timeRecord = list.get(list.size() - 1);
                        timeRecord.setStopTime(moveEntity.getRecordTime());
                    }
                }
            }
            return list;
        } else {
            return new ArrayList<>();
        }
    }

}
